package com.blb.day20231107login.config;

import com.blb.day20231107login.entity.ResponseResult;
import com.blb.day20231107login.entity.User;
import com.blb.day20231107login.service.IUserService;
import com.blb.day20231107login.util.ApplicationContextUtils;
import com.blb.day20231107login.util.JwtUtils;
import com.blb.day20231107login.util.RsaUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.jsonwebtoken.ExpiredJwtException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;

import javax.annotation.Resource;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;

/**
 * 用于验证token的过滤器
 */
@Slf4j
public class TokenAuthenticationFilter extends BasicAuthenticationFilter {

    /**
     * 请求头名称
     */
    public static final String ACCESS_TOKEN_HEADER = "Authorization";
    public static final String REFRESH_TOKEN_HEADER = "RefreshToken";

    //通过IOC容器获得bean对象
    private IUserService userService = ApplicationContextUtils
            .getApplicationContext().getBean(IUserService.class);

    public TokenAuthenticationFilter(AuthenticationManager authenticationManager) {
        super(authenticationManager);
    }

    /**
     * 过滤请求和响应
     */
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
        //获得请求头中的token
        String accessToken = request.getHeader(ACCESS_TOKEN_HEADER);
        if(accessToken == null){
            throw new RuntimeException("accessToken为空");
        }
        String username = null;
        try {
            //解析请求头
            username = JwtUtils.getUsernameFromToken(accessToken, RsaUtils.publicKey);
//            if(1 == 1) {
//                throw new ExpiredJwtException(null,null,null);
//            }
            //解析成功就创建令牌，交给security，让请求通信
            List<GrantedAuthority> authorities = userService.getAuthoritiesByUsername(username);
            UsernamePasswordAuthenticationToken uToken = new UsernamePasswordAuthenticationToken(username,"",authorities);
            SecurityContextHolder.getContext().setAuthentication(uToken);
        }catch (ExpiredJwtException ex){
            log.info("access-token过期开始刷新..");
            String refreshToken = request.getHeader(REFRESH_TOKEN_HEADER);
            if(refreshToken == null){
                throw new RuntimeException("refreshToken为空");
            }
            try {
                //access-token过期后，去解析refresh-token
                String s = JwtUtils.getUsernameFromToken(refreshToken, RsaUtils.publicKey);
                log.info("refresh-token解析成功",s);
                //如果能解析成功，就重新生成access-token和refresh-token
                accessToken = JwtUtils.generateToken(username, RsaUtils.privateKey, JwtUtils.EXPIRE_MINUTES);
                String uid = accessToken.substring(0,10);
                refreshToken = JwtUtils.generateToken(uid, RsaUtils.privateKey, JwtUtils.EXPIRE_MINUTES * 2);
                //发送给客户端，客户端重新保存
                HashMap<String,String> tokens = new HashMap<>();
                tokens.put("accessToken",accessToken);
                tokens.put("refreshToken",refreshToken);
                //让自定义响应头可见
                response.setHeader("Access-Control-Expose-Headers","tokens");
                //把两个token放到响应头和响应数据一起返回
                response.setHeader("tokens",new ObjectMapper().writeValueAsString(tokens));
            }catch (ExpiredJwtException ex1){
                log.error("refresh-token过期",ex1);
            }
        }catch (Exception ex){
            log.error("解析token失败",ex);
        }
        //执行下一个过滤器
        chain.doFilter(request,response);
    }
}
